<i18n locale="en" lang="yaml">
recentTaskCount: 'recent {n} task | recent {n} tasks'
shortcutDays  : '{n} day | {n} days'
</i18n>

<i18n locale="zh-CN" lang="yaml">
Add Cron Job  : 添加定时任务
Setup Cron Job: 配置定时任务

Customize ID: 定制 ID
Execute     : 执行
Arguments   : 参数指定
Task Record : 任务记录
Keep        : 保留
Tags        : 标签
Add Tag     : 添加标签
Weekdays    : 按周重复
Months      : 按月重复
Days        : 按天重复
Hours       : 按小时重复
Minutes     : 按分钟重复
Expires     : 有效期
Note        : 备注

Simple Mode                      : 简单模式
Custom Mode                      : 自定义模式
Fill in Cron expressions directly: 直接填写 Cron 表达式

Cron Expr      : Cron 表达式
Fixed Cron Expr: 固定 Cron 表达式

Every minute     : 每分钟
Every 2 minutes  : 每 2 分钟
Every 3 minutes  : 每 3 分钟
Every 5 minutes  : 每 5 分钟
Every 10 minutes : 每 10 分钟
Every 15 minutes : 每 15 分钟
Every 30 minutes : 每 30 分钟
Every hour       : 每小时
Every 2 hours    : 每 2 小时
Every 3 hours    : 每 3 小时
Every 6 hours    : 每 6 小时
Every 8 hours    : 每 8 小时
Every 12 hours   : 每 12 小时
Every day        : 每天
Every month      : 每月
Every 2 months   : 每 2 个月
Every 3 months   : 每 3 个月
Every 6 months   : 每 6 个月
Every weekday    : 不限星期
SUN              : 周日
MON              : 周一
TUE              : 周二
WED              : 周三
THU              : 周四
FRI              : 周五
SAT              : 周六

'JSON formated arguments (**kwargs)': 'JSON格式的参数（**kwargs）'
The Func accepts extra arguments not listed above: 本函数允许传递额外的自定义函数参数

'ID must starts with "{prefix}"'                                          : 'ID 必须以"{prefix}"开头'
'Only numbers, alphabets, dot(.), underscore(_) and hyphen(-) are allowed': 只能输入数字、英文、点（.）、下划线（_）以及连字符（-）
Please select Func                                                        : 请选择执行函数
'Please input arguments, input "{}" when no argument'                     : '请输入参数，无参数时填写 "{}"'
Date cannot earlier than 1970                                             : 日期不能早于 1970 年
Date cannot later than 2099                                               : 日期不能晚于 2099 年
Cron expression does support second field                                 : Cron 表达式不支持秒字段
Invalid Cron expression                                                   : Cron 表达式不正确

Cron Job created: 定时任务配置已创建
Cron Job saved  : 定时任务配置已保存
Cron Job deleted: 定时任务配置已删除

Are you sure you want to delete the Cron Job?: 是否确认删除此定时任务？
Invalid argument format                      : 参数格式不正确

recentTaskCount: '{n} 个近期任务'
shortcutDays   : '{n} 天'
</i18n>

<!-- Generated by OpenCC START -->
<i18n locale="zh-HK" lang="yaml">
Add Cron Job: 添加定時任務
Add Tag: 添加標籤
Are you sure you want to delete the Cron Job?: 是否確認刪除此定時任務？
Arguments: 參數指定
Cron Expr: Cron 表達式
Cron Job created: 定時任務配置已創建
Cron Job deleted: 定時任務配置已刪除
Cron Job saved: 定時任務配置已保存
Cron expression does support second field: Cron 表達式不支持秒字段
Custom Mode: 自定義模式
Customize ID: 定製 ID
Date cannot earlier than 1970: 日期不能早於 1970 年
Date cannot later than 2099: 日期不能晚於 2099 年
Days: 按天重複
Every 10 minutes: 每 10 分鐘
Every 12 hours: 每 12 小時
Every 15 minutes: 每 15 分鐘
Every 2 hours: 每 2 小時
Every 2 minutes: 每 2 分鐘
Every 2 months: 每 2 個月
Every 3 hours: 每 3 小時
Every 3 minutes: 每 3 分鐘
Every 3 months: 每 3 個月
Every 30 minutes: 每 30 分鐘
Every 5 minutes: 每 5 分鐘
Every 6 hours: 每 6 小時
Every 6 months: 每 6 個月
Every 8 hours: 每 8 小時
Every day: 每天
Every hour: 每小時
Every minute: 每分鐘
Every month: 每月
Every weekday: 不限星期
Execute: 執行
Expires: 有效期
FRI: 週五
Fill in Cron expressions directly: 直接填寫 Cron 表達式
Fixed Cron Expr: 固定 Cron 表達式
Hours: 按小時重複
ID must starts with "{prefix}": ID 必須以"{prefix}"開頭
Invalid Cron expression: Cron 表達式不正確
Invalid argument format: 參數格式不正確
JSON formated arguments (**kwargs): JSON格式的參數（**kwargs）
Keep: 保留
MON: 週一
Minutes: 按分鐘重複
Months: 按月重複
Note: 備註
Only numbers, alphabets, dot(.), underscore(_) and hyphen(-) are allowed: 只能輸入數字、英文、點（.）、下劃線（_）以及連字符（-）
Please input arguments, input "{}" when no argument: 請輸入參數，無參數時填寫 "{}"
Please select Func: 請選擇執行函數
SAT: 週六
SUN: 週日
Setup Cron Job: 配置定時任務
Simple Mode: 簡單模式
THU: 週四
TUE: 週二
Tags: 標籤
Task Record: 任務記錄
The Func accepts extra arguments not listed above: 本函數允許傳遞額外的自定義函數參數
WED: 週三
Weekdays: 按周重複
recentTaskCount: '{n} 個近期任務'
shortcutDays: '{n} 天'
</i18n>
<i18n locale="zh-TW" lang="yaml">
Add Cron Job: 新增定時任務
Add Tag: 新增標籤
Are you sure you want to delete the Cron Job?: 是否確認刪除此定時任務？
Arguments: 引數指定
Cron Expr: Cron 表示式
Cron Job created: 定時任務配置已建立
Cron Job deleted: 定時任務配置已刪除
Cron Job saved: 定時任務配置已儲存
Cron expression does support second field: Cron 表示式不支援秒欄位
Custom Mode: 自定義模式
Customize ID: 定製 ID
Date cannot earlier than 1970: 日期不能早於 1970 年
Date cannot later than 2099: 日期不能晚於 2099 年
Days: 按天重複
Every 10 minutes: 每 10 分鐘
Every 12 hours: 每 12 小時
Every 15 minutes: 每 15 分鐘
Every 2 hours: 每 2 小時
Every 2 minutes: 每 2 分鐘
Every 2 months: 每 2 個月
Every 3 hours: 每 3 小時
Every 3 minutes: 每 3 分鐘
Every 3 months: 每 3 個月
Every 30 minutes: 每 30 分鐘
Every 5 minutes: 每 5 分鐘
Every 6 hours: 每 6 小時
Every 6 months: 每 6 個月
Every 8 hours: 每 8 小時
Every day: 每天
Every hour: 每小時
Every minute: 每分鐘
Every month: 每月
Every weekday: 不限星期
Execute: 執行
Expires: 有效期
FRI: 週五
Fill in Cron expressions directly: 直接填寫 Cron 表示式
Fixed Cron Expr: 固定 Cron 表示式
Hours: 按小時重複
ID must starts with "{prefix}": ID 必須以"{prefix}"開頭
Invalid Cron expression: Cron 表示式不正確
Invalid argument format: 引數格式不正確
JSON formated arguments (**kwargs): JSON格式的引數（**kwargs）
Keep: 保留
MON: 週一
Minutes: 按分鐘重複
Months: 按月重複
Note: 備註
Only numbers, alphabets, dot(.), underscore(_) and hyphen(-) are allowed: 只能輸入數字、英文、點（.）、下劃線（_）以及連字元（-）
Please input arguments, input "{}" when no argument: 請輸入引數，無引數時填寫 "{}"
Please select Func: 請選擇執行函式
SAT: 週六
SUN: 週日
Setup Cron Job: 配置定時任務
Simple Mode: 簡單模式
THU: 週四
TUE: 週二
Tags: 標籤
Task Record: 任務記錄
The Func accepts extra arguments not listed above: 本函式允許傳遞額外的自定義函式引數
WED: 週三
Weekdays: 按周重複
recentTaskCount: '{n} 個近期任務'
shortcutDays: '{n} 天'
</i18n>
<!-- Generated by OpenCC END -->

<template>
  <el-dialog
    id="ScriptSetSetup"
    :visible.sync="show"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    width="750px">

    <template slot="title">
      {{ pageTitle }} <code class="text-main">{{ data.func_title }}</code>
    </template>

    <el-container direction="vertical">
      <el-main>
        <div class="setup-form">
          <el-form ref="form" label-width="135px" :model="form" :rules="formRules">
            <el-form-item :label="$t('Customize ID')" prop="useCustomId" v-if="pageMode === 'add'">
              <el-switch v-model="useCustomId"></el-switch>
            </el-form-item>

            <el-form-item label="ID" prop="id" v-show="useCustomId" v-if="pageMode === 'add'">
              <el-input
                maxlength="60"
                v-model="form.id">
              </el-input>
            </el-form-item>

            <el-form-item :label="$t('Execute')" prop="funcId">
              <el-cascader ref="funcCascader"
                popper-class="code-font"
                placeholder="--"
                filterable
                :filter-method="common.funcCascaderFilter"
                v-model="form.funcId"
                :options="funcCascader"
                :props="{ expandTrigger: 'hover', emitPath: false, multiple: false }"
                @change="autoFillFuncCallKwargsJSON">
                </el-cascader>
            </el-form-item>

            <el-form-item :label="$t('Arguments')" prop="funcCallKwargsJSON">
              <el-input
                type="textarea"
                v-model="form.funcCallKwargsJSON"
                resize="none"
                :autosize="{ minRows: 2 }"></el-input>
              <InfoBlock :title="$t('JSON formated arguments (**kwargs)')" />

              <InfoBlock v-if="apiCustomKwargsSupport" type="success" :title="$t('The Func accepts extra arguments not listed above')" />
            </el-form-item>

            <el-form-item :label="$t('Tags')" prop="tagsJSON">
              <el-tag v-for="t in form.tagsJSON" :key="t" type="warning" size="small" closable @close="removeTag(t)">{{ t }}</el-tag>
              <el-input v-if="showAddTag" ref="newTag"
                v-model="newTag"
                size="mini"
                @keyup.enter.native="addTag"
                @blur="addTag"></el-input>
              <el-button v-else
                type="text"
                @click="openAddTagInput">{{ $t('Add Tag') }}</el-button>
            </el-form-item>

            <el-form-item :label="$t('Task Record')">
              <span class="task-record-limit-prefix">{{ $t('Keep') }} </span>
              <el-input-number class="task-record-limit-input"
                :min="$store.getters.SYSTEM_INFO('_TASK_RECORD_LIMIT_MIN')"
                :max="$store.getters.SYSTEM_INFO('_TASK_RECORD_LIMIT_MAX')"
                :step="10"
                :precision="0"
                v-model="form.taskRecordLimit"></el-input-number>
              <span class="task-record-limit-unit">{{ $tc('recentTaskCount', form.taskRecordLimit, { n: '' }) }} </span>
              <el-link class="right-button" type="primary" @click.stop="form.taskRecordLimit = $store.getters.SYSTEM_INFO('_TASK_RECORD_FUNC_LIMIT_CRON_JOB')">{{ $t('Restore Default') }}</el-link>
            </el-form-item>

            <!-- Cron expression -->
            <template v-if="!fixedCronExpr">
              <el-form-item>
                <el-radio-group v-model="cronExprBuildMode" size="mini">
                  <el-radio-button label="simple">{{ $t('Simple Mode') }}</el-radio-button>
                  <el-radio-button label="advanced">{{ $t('Custom Mode') }}</el-radio-button>
                </el-radio-group>
              </el-form-item>

              <template v-if="cronExprBuildMode === 'simple'">
                <el-form-item :label="$t('Cron Expr')">
                  <span class="cron-expr-parts cron-expr-parts-minutes">{{ uiCronExprParts.minutes }}</span>
                  <span class="cron-expr-parts cron-expr-parts-hours">{{ uiCronExprParts.hours }}</span>
                  <span class="cron-expr-parts cron-expr-parts-days">{{ uiCronExprParts.days }}</span>
                  <span class="cron-expr-parts cron-expr-parts-months">{{ uiCronExprParts.months }}</span>
                  <span class="cron-expr-parts cron-expr-parts-weeks">{{ uiCronExprParts.weeks }}</span>
                </el-form-item>

                <el-form-item :label="$t('Minutes')">
                  <el-checkbox-group v-model="formCronExpr.minutes">
                    <template v-for="(item, index) in MINUTES">
                      <br v-if="item === 'sep'">
                      <el-checkbox v-else
                        border
                        class="cron-expr-item-checkbox"
                        :key="item.expr"
                        :label="item.expr"
                        :size="index === 0 ? null : 'mini'"
                        @change="onUICronExprChange">{{ item.name }}</el-checkbox>
                    </template>
                  </el-checkbox-group>
                </el-form-item>

                <el-form-item :label="$t('Hours')">
                  <el-checkbox-group v-model="formCronExpr.hours">
                    <template v-for="(item, index) in HOURS">
                      <br v-if="item === 'sep'">
                      <el-checkbox v-else
                        border
                        class="cron-expr-item-checkbox"
                        :key="item.expr"
                        :label="item.expr"
                        :size="index === 0 ? null : 'mini'"
                        @change="onUICronExprChange">{{ item.name }}</el-checkbox>
                    </template>
                  </el-checkbox-group>
                </el-form-item>

                <el-form-item :label="$t('Days')">
                  <el-checkbox-group v-model="formCronExpr.days">
                    <template v-for="(item, index) in DAYS">
                      <br v-if="item === 'sep'">
                      <el-checkbox v-else
                        border
                        class="cron-expr-item-checkbox"
                        :key="item.expr"
                        :label="item.expr"
                        :size="index === 0 ? null : 'mini'"
                        @change="onUICronExprChange">{{ item.name }}</el-checkbox>
                    </template>
                  </el-checkbox-group>
                </el-form-item>

                <el-form-item :label="$t('Months')">
                  <el-checkbox-group v-model="formCronExpr.months">
                    <template v-for="(item, index) in MONTHS">
                      <br v-if="item === 'sep'">
                      <el-checkbox v-else
                        border
                        class="cron-expr-item-checkbox"
                        :key="item.expr"
                        :label="item.expr"
                        :size="index === 0 ? null : 'mini'"
                        @change="onUICronExprChange">{{ item.name }}</el-checkbox>
                    </template>
                  </el-checkbox-group>
                </el-form-item>

                <el-form-item :label="$t('Weekdays')">
                  <el-checkbox-group v-model="formCronExpr.weeks">
                    <template v-for="(item, index) in WEEKS">
                      <br v-if="item === 'sep'">
                      <el-checkbox v-else
                        border
                        class="cron-expr-item-checkbox"
                        :key="item.expr"
                        :label="item.expr"
                        :size="index === 0 ? null : 'mini'"
                        @change="onUICronExprChange">{{ item.name }}</el-checkbox>
                    </template>
                  </el-checkbox-group>
                </el-form-item>

                <el-form-item :label="$t('Cron Expr')">
                  <span class="cron-expr-parts cron-expr-parts-minutes">{{ uiCronExprParts.minutes }}</span>
                  <span class="cron-expr-parts cron-expr-parts-hours">{{ uiCronExprParts.hours }}</span>
                  <span class="cron-expr-parts cron-expr-parts-days">{{ uiCronExprParts.days }}</span>
                  <span class="cron-expr-parts cron-expr-parts-months">{{ uiCronExprParts.months }}</span>
                  <span class="cron-expr-parts cron-expr-parts-weeks">{{ uiCronExprParts.weeks }}</span>
                </el-form-item>
              </template>
              <el-form-item v-show="cronExprBuildMode === 'advanced'" :label="$t('Cron Expr')" prop="cronExpr">
                <el-input maxlength="60" v-model="form.cronExpr" :placeholder="$t('Fill in Cron expressions directly')"></el-input>
              </el-form-item>
            </template>
            <el-form-item v-else :label="$t('Fixed Cron Expr')">
              <span class="cron-expr-parts cron-expr-parts-minutes">{{ fixedCronExprParts.minutes }}</span>
              <span class="cron-expr-parts cron-expr-parts-hours">{{ fixedCronExprParts.hours }}</span>
              <span class="cron-expr-parts cron-expr-parts-days">{{ fixedCronExprParts.days }}</span>
              <span class="cron-expr-parts cron-expr-parts-months">{{ fixedCronExprParts.months }}</span>
              <span class="cron-expr-parts cron-expr-parts-weeks">{{ fixedCronExprParts.weeks }}</span>
            </el-form-item>
            <!-- End of Cron expression config -->

            <el-form-item :label="$t('Expires')" prop="expireTime">
              <el-date-picker
                v-model="form.expireTime"
                type="datetime"
                align="left"
                format="yyyy-MM-dd HH:mm:ss"
                default-time="23:59:59"
                :clearable="true"
                :picker-options="datetimePickerOptions">
              </el-date-picker>
            </el-form-item>

            <el-form-item :label="$t('Note')">
              <el-input :placeholder="$t('Optional')"
                type="textarea"
                resize="none"
                :autosize="{minRows: 2}"
                maxlength="5000"
                v-model="form.note"></el-input>
            </el-form-item>

            <el-form-item class="setup-footer">
              <el-link type="danger" class="float-left" v-if="pageMode === 'setup'" @click="deleteData">{{ $t('Delete') }}</el-link>
              <el-button type="primary" v-prevent-re-click @click="submitData">{{ $t('Save') }}</el-button>
            </el-form-item>
          </el-form>
        </div>
      </el-main>
    </el-container>
  </el-dialog>
</template>

<script>
import * as CronParser from 'cron-parser';

export default {
  name: 'CronJobSetup',
  components: {
  },
  watch: {
    show(val) {
      if (val && this.$refs.form) {
        this.$refs.form.clearValidate();
      }

      if (!val) {
        this.$root.$emit('reload.cronJobList');
      }
    },
    useCustomId(val) {
      if (val) {
        this.form.id = `my-cron-job`;
      } else {
        this.form.id = null;
      }
    },
  },
  methods: {
    async loadData(id) {
      if (!id) {
        this.pageMode = 'add';
        const defaultFormCronExpr = {
          weeks  : ['*'],
          months : ['*'],
          days   : ['*'],
          hours  : ['*'],
          minutes: ['*/5'],
        };
        this.formCronExprCache = this.T.jsonCopy(defaultFormCronExpr);
        this.formCronExpr      = this.T.jsonCopy(defaultFormCronExpr);
        this.T.jsonClear(this.form);
        this.form.taskRecordLimit = this.$store.getters.SYSTEM_INFO('_TASK_RECORD_FUNC_LIMIT_CRON_JOB');
        this.data = {};
        this.cronExprBuildMode = 'simple';

      } else {
        this.pageMode = 'setup';
        this.data.id = id;

        let apiRes = await this.T.callAPI_getOne('/api/v1/cron-jobs/do/list', this.data.id);
        if (!apiRes || !apiRes.ok) return;

        this.data = apiRes.data;
        this.cronExprBuildMode = this.matchSimpleMode ? 'simple' : 'advanced';

        let nextForm = {};
        Object.keys(this.form).forEach(f => nextForm[f] = this.data[f]);
        nextForm.funcCallKwargsJSON = JSON.stringify(nextForm.funcCallKwargsJSON, null, 2);
        nextForm.tagsJSON = nextForm.tagsJSON || [];

        this.form = nextForm;

        if (this.data.cronExpr) {
          // Split Cron expression
          this.data.cronExpr.split(' ').forEach((d, index) => {
            let f = this.CRON_EXPR_PARTS_MAP[index];
            this.formCronExpr[f] = d.split(',');
          });
          this.formCronExprCache = this.T.jsonCopy(this.formCronExpr);
        }
      }

      // Get Func list
      let funcList = await this.common.getFuncList();

      for (var funcId in funcList.map) {
        let f = funcList.map[funcId];
        f.isFixedCronExpr = !!(f.extraConfigJSON && f.extraConfigJSON.fixedCronExpr);
        if (f.isFixedCronExpr) {
          f.label += ' ' + this.$t('(') + this.$t('Fixed Cron Expr') + this.$t(')');
        }
      }

      this.funcMap      = funcList.map;
      this.funcCascader = funcList.cascader;

      this.show = true;
    },
    async submitData() {
      try {
        await this.$refs.form.validate();
      } catch(err) {
        return console.error(err);
      }

      switch(this.pageMode) {
        case 'add':
          return await this.addData();
        case 'setup':
          return await this.modifyData();
      }
    },
    async addData() {
      let _formData = this.T.jsonCopy(this.form);
      let opt = {
        body    : { data: _formData },
        feedback: { okMessage: this.$t('Cron Job created') },
      };

      // Add Func calling parameter kwargsJSON
      try {
        opt.body.data.funcCallKwargsJSON = JSON.parse(this.form.funcCallKwargsJSON);
      } catch(err) {
        return this.T.alert(`${this.$t('Invalid argument format')}<br>${err.toString()}`);
      }

      // Simple mode for gen Cron expression
      if (!this.fixedCronExpr && this.cronExprBuildMode === 'simple') {
        opt.body.data.cronExpr = this.uiCronExpr.trim() || null;
      }

      let apiRes = await this.T.callAPI('post', '/api/v1/cron-jobs/do/add', opt);
      if (!apiRes || !apiRes.ok) return;

      this.$store.commit('updateHighlightedTableDataId', apiRes.data.id);
      this.show = false;
    },
    async modifyData() {
      let _formData = this.T.jsonCopy(this.form);
      delete _formData.id;

      let opt = {
        params  : { id: this.data.id },
        body    : { data: _formData },
        feedback: { okMessage: this.$t('Cron Job saved') },
      };

      // Add Func calling kwargs
      try {
        opt.body.data.funcCallKwargsJSON = JSON.parse(this.form.funcCallKwargsJSON);
      } catch(err) {
        return this.T.alert(`${this.$t('Invalid argument format')}<br>${err.toString()}`);
      }

      // Simple mode for gen Cron expression
      if (!this.fixedCronExpr && this.cronExprBuildMode === 'simple') {
        opt.body.data.cronExpr = this.uiCronExpr.trim() || null;
      }

      let apiRes = await this.T.callAPI('post', '/api/v1/cron-jobs/:id/do/modify', opt);
      if (!apiRes || !apiRes.ok) return;

      this.$store.commit('updateHighlightedTableDataId', apiRes.data.id);
      this.show = false;
    },
    async deleteData() {
      if (!await this.T.confirm(this.$t('Are you sure you want to delete the Cron Job?'))) return;

      let apiRes = await this.T.callAPI('/api/v1/cron-jobs/:id/do/delete', {
        params  : { id: this.data.id },
        feedback: { okMessage: this.$t('Cron Job deleted') },
      });
      if (!apiRes || !apiRes.ok) return;

      this.show = false;
    },
    autoFillFuncCallKwargsJSON(funcId) {
      // Fill Func calling kwargs automatically
      let parameters = this.funcMap[funcId].argsJSON
                    || Object.keys(this.funcMap[funcId].kwargsJSON);

      let example = {};
      parameters.forEach(p => {
        if (p.indexOf('**') === 0) {
          // TEMP: skip **kwargs parameter
        } else {
          example[p] = p.toUpperCase();
        }
      });

      this.form.funcCallKwargsJSON = JSON.stringify(example, null, 2);
    },
    removeTag(tag) {
      this.form.tagsJSON.splice(this.form.tagsJSON.indexOf(tag), 1);
    },
    openAddTagInput() {
      this.showAddTag = true;
      this.$nextTick(_ => {
        this.$refs.newTag.$refs.input.focus();
      });
    },
    addTag() {
      let newTag = this.newTag;
      if (newTag) {
        if (!Array.isArray(this.form.tagsJSON)) {
          this.$set(this.form, 'tagsJSON', []);
        }
        this.form.tagsJSON.push(newTag);
      }
      this.showAddTag = false;
      this.newTag     = '';
    },
    onUICronExprChange() {
      let sortFunc = (a, b) => {
        return parseInt(a) - parseInt(b);
      }
      let hasStarExpr = part => {
        if (this.T.isNothing(part)) return false;
        for (let i = 0; i < part.length; i++) {
          if (part[i].indexOf('*') >= 0) return true;
        }
        return false;
      }

      ['weeks', 'months', 'days', 'hours', 'minutes'].forEach(part => {
        let defaultExpr = this[part.toUpperCase()][0].expr;

        let oldPart = this.formCronExprCache[part];
        let newPart = this.formCronExpr[part];
        if (oldPart.length + newPart.length > 0 && oldPart.join(',') === newPart.join(',')) return;

        if (newPart.length <= 0) {
          this.formCronExpr[part] = [defaultExpr];
        } else if (hasStarExpr(newPart)) {
          this.formCronExpr[part] = [newPart.pop()];
        }

        this.formCronExprCache[part].sort(sortFunc);
        this.formCronExpr[part].sort(sortFunc);
      });

      this.formCronExprCache = this.T.jsonCopy(this.formCronExpr);
    },
    _getNumberList(fixedItems, start, end, step, wrapEach) {
      step = step || 1;

      let list = fixedItems || [];
      let count = 0;
      for (let i = start; i <= end; i+=step) {
        count++;
        list.push({
          expr: i.toString(),
          name: this.T.padZero(i, 2),
        });

        if (count % wrapEach === 0) {
          list.push('sep');
        }
      }
      return list;
    },
  },
  computed: {
    CRON_EXPR_PARTS_MAP() {
      return {
        0: 'minutes',
        1: 'hours',
        2: 'days',
        3: 'months',
        4: 'weeks',
      };
    },

    MINUTES() {
      return this._getNumberList([
        {expr: '*', name: this.$t('Every minute')},
        'sep',
        {expr: '*/2', name: this.$t('Every 2 minutes')},
        {expr: '*/3', name: this.$t('Every 3 minutes')},
        {expr: '*/5', name: this.$t('Every 5 minutes')},
        'sep',
        {expr: '*/10', name: this.$t('Every 10 minutes')},
        {expr: '*/15', name: this.$t('Every 15 minutes')},
        {expr: '*/30', name: this.$t('Every 30 minutes')},
        'sep',
      ], 0, 59, 5, 6);
    },
    HOURS() {
      return this._getNumberList([
        {expr: '*', name: this.$t('Every hour')},
        'sep',
        {expr: '*/2', name: this.$t('Every 2 hours')},
        {expr: '*/3', name: this.$t('Every 3 hours')},
        {expr: '*/6', name: this.$t('Every 6 hours')},
        {expr: '*/8', name: this.$t('Every 8 hours')},
        'sep',
      ], 0, 23, 1, 6);
    },
    DAYS() {
      return this._getNumberList([
        {expr: '*', name: this.$t('Every day')},
        'sep',
      ], 1, 31, 1, 5);
    },
    MONTHS() {
      return this._getNumberList([
        {expr: '*', name: this.$t('Every month')},
        'sep',
        {expr: '*/3', name: this.$t('Every 3 months')},
        {expr: '*/6', name: this.$t('Every 6 months')},
        'sep',
      ], 1, 12, 1, 6);
    },
    WEEKS() {
      return [
        {expr: '*', name: this.$t('Every weekday')},
        'sep',
        {expr: '1', name: this.$t('MON')},
        {expr: '2', name: this.$t('TUE')},
        {expr: '3', name: this.$t('WED')},
        {expr: '4', name: this.$t('THU')},
        {expr: '5', name: this.$t('FRI')},
        'sep',
        {expr: '6', name: this.$t('SAT')},
        {expr: '0', name: this.$t('SUN')},
      ];
    },
    matchSimpleMode() {
      if (!this.data || !this.data.cronExpr) return false;

      let cronExprParts = this.data.cronExpr.split(' ');
      for (let i = 0; i < cronExprParts.length; i++ ) {
        let _field = this.CRON_EXPR_PARTS_MAP[i];
        let contabSimpleModeOptions = this[_field.toUpperCase()];
        let _partList = cronExprParts[i].split(',');

        if (contabSimpleModeOptions.filter(item => _partList.indexOf(item.expr) >= 0).length != _partList.length) {
          return false;
        }
      }
      return true;
    },

    pageTitle() {
      const _map = {
        setup: this.$t('Setup Cron Job'),
        add  : this.$t('Add Cron Job'),
      };
      return _map[this.pageMode];
    },
    apiCustomKwargsSupport() {
      let funcId = this.form.funcId;
      if (!funcId) return false;
      if (!this.funcMap[funcId]) return false;

      for (let k in this.funcMap[funcId].kwargsJSON) {
        if (k.indexOf('**') === 0) return true;
      }
      return false;
    },
    fixedCronExpr() {
      let selectedFunc = this.funcMap[this.form.funcId];
      if (selectedFunc
          && selectedFunc.extraConfigJSON
          && selectedFunc.extraConfigJSON.fixedCronExpr) {
        return selectedFunc.extraConfigJSON.fixedCronExpr;
      } else {
        return null;
      }
    },
    fixedCronExprParts() {
      if (!this.fixedCronExpr) {
        return null;
      } else {
        let _parts = this.fixedCronExpr.split(' ');
        return {
          minutes: _parts[0],
          hours  : _parts[1],
          days   : _parts[2],
          months : _parts[3],
          weeks  : _parts[4],
        };
      }
    },
    uiCronExprParts() {
      return {
        minutes: this.formCronExpr.minutes.join(','),
        hours  : this.formCronExpr.hours.join(','),
        days   : this.formCronExpr.days.join(','),
        months : this.formCronExpr.months.join(','),
        weeks  : this.formCronExpr.weeks.join(','),
      };
    },
    uiCronExpr() {
      return [
        this.uiCronExprParts.minutes,
        this.uiCronExprParts.hours,
        this.uiCronExprParts.days,
        this.uiCronExprParts.months,
        this.uiCronExprParts.weeks,
      ].join(' ').trim();
    },
    datetimePickerOptions() {
      const now = new Date().getTime();
      const shortcutDaysList = [1, 3, 7, 30, 90, 365];
      let shortcuts = [];
      shortcutDaysList.forEach((days) => {
        let date = this.M().add(days, 'days').hours(23).minutes(59).seconds(59).toDate();

        shortcuts.push({
          text: this.$tc('shortcutDays', days),
          onClick(picker) {
            picker.$emit('pick', date);
          }
        });
      });

      return {
        shortcuts: shortcuts
      }
    },
  },
  props: {
  },
  data() {
    let errorMessage_funcCallKwargsJSON = this.$t('Please input arguments, input "{}" when no argument');

    return {
      show    : false,
      pageMode: null,

      data        : {},
      funcMap     : {},
      funcCascader: [],

      useCustomId: false,
      showAddTag : false,
      newTag     : '',

      cronExprBuildMode: 'simple',

      form: {
        id                : null,
        funcId            : null,
        funcCallKwargsJSON: null,
        cronExpr          : null,
        tagsJSON          : [],
        expireTime        : null,
        taskRecordLimit   : this.$store.getters.SYSTEM_INFO('_TASK_RECORD_FUNC_LIMIT_CRON_JOB'),
        note              : null,
      },

      formCronExprCache: {
        weeks  : [],
        months : [],
        days   : [],
        hours  : [],
        minutes: [],
      },
      formCronExpr: {
        weeks  : [],
        months : [],
        days   : [],
        hours  : [],
        minutes: [],
      },

      formRules: {
        id: [
          {
            trigger: 'change',
            validator: (rule, value, callback) => {
              if (this.T.notNothing(value)) {
                if (!value.match(/^[0-9a-zA-Z\.\-\_]+$/g)) {
                  return callback(new Error(this.$t('Only numbers, alphabets, dot(.), underscore(_) and hyphen(-) are allowed')));
                }
              }
              return callback();
            },
          }
        ],
        funcId: [
          {
            trigger : 'blur',
            message : this.$t('Please select Func'),
            required: true,
          },
        ],
        expireTime: [
          {
            trigger: 'change',
            validator: (rule, value, callback) => {
              if (value) {
                let ts = this.M(value).unix();
                if (ts < this.T.MIN_UNIX_TIMESTAMP) {
                  return callback(new Error(this.$t('Date cannot earlier than 2000')));
                } else if (ts > this.T.MAX_UNIX_TIMESTAMP) {
                  return callback(new Error(this.$t('Date cannot later than 2099')));
                }
              }
              return callback();
            },
          }
        ],
        funcCallKwargsJSON: [
          {
            trigger : 'blur',
            message : errorMessage_funcCallKwargsJSON,
            required: true,
          },
          {
            trigger  : 'change',
            validator: (rule, value, callback) => {
              try {
                if (value) {
                  let j = JSON.parse(value);
                  if (Array.isArray(j)) {
                    return callback(new Error(errorMessage_funcCallKwargsJSON));
                  }
                }
                return callback();

              } catch(err) {
                return callback(new Error(errorMessage_funcCallKwargsJSON));
              }
            },
          }
        ],
        cronExpr: [
          {
            trigger: 'change',
            validator: (rule, value, callback) => {
              if (this.cronExprBuildMode === 'advanced' && value) {
                try {
                  let parsedSecond = CronParser.parseExpression(value).fields.second;
                  if (parsedSecond.length !== 1 || parsedSecond[0] !== 0) {
                    return callback(new Error(this.$t('Cron expression does support second field')));
                  }

                } catch(err) {
                  return callback(new Error(this.$t('Invalid Cron expression')));
                }
              }
              return callback();
            },
          }
        ],
      }
    }
  },
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.task-record-limit-input {
  width: 180px;
}
.task-record-limit-prefix {
  color: grey;
  padding-right: 10px;
}
.task-record-limit-unit {
  color: grey;
  padding-left: 10px;
}
.task-record-limit-unit > span {
  width: 35px;
  display: inline-block;
}

.cron-expr-parts {
  font-size: 35px;
  margin-right: 20px;
  vertical-align: middle;
}
.cron-expr-parts-weeks {
  color: brown;
}
.cron-expr-parts-months {
  color: red;
}
.cron-expr-parts-days {
  color: seagreen;
}
.cron-expr-parts-hours {
  color: magenta;
}
.cron-expr-parts-minutes {
  color: orange;
}

.el-checkbox.cron-expr-item-checkbox {
  margin-left : 5px !important;
  margin-right: 0 !important;
  min-width: 75px;
}
</style>
